#include "board_com.h"
#include "RGB.h"
#include "beep.h"
#include "can_common.h"
#include "crc8.h"
#include "drivers/dev_can.h"
#include "offline.h"
#include "rtdef.h"
#include "rtklibc.h"
#include "rtthread.h"
#include "rttypes.h"
#include "robotdef.h"

extern rt_device_t can1_bus;  /* CAN 设备句柄 */
extern rt_device_t can2_bus;


#define LOG_TAG              "board_com"
#define LOG_LVL              LOG_LVL_DBG
#include <ulog.h>


board_com_s board_com;
int board_com_init(void)
{
    offline_manage_obj board;
    board.enable = OFFLINE_ENABLE;
    board.online_state = STATE_OFFLINE;
    board.error_level = OFFLINE_ERROR_LEVEL;
    board.last_time = rt_tick_get();
    board.offline_time = 1000;

    board_com.raw_sendbuf[0] = CAN_COMM_HEADER;            // head,直接设置避免每次发送都要重新赋值,下面的tail同理

    
#ifdef BOARD_SMALL_YAW_1
    board.event = OFFLINE_BOARD_BIG_YAW;
    board.beep_times = 6;
    offline_event_init(board);

    board.event = OFFLINE_BOARD_CHASSIS;
    board.beep_times = 6;
    offline_event_init(board);
#endif 
#ifdef BOARD_SMALL_YAW_2
    board.event = OFFLINE_BOARD_BIG_YAW;
    board.beep_times = 6;
    offline_event_init(board);

    board.event = OFFLINE_BOARD_CHASSIS;
    board.beep_times = 6;
    offline_event_init(board);
#endif 
#ifdef BOARD_BIG_YAW
    board.event = OFFLINE_BOARD_SMALL_YAW_1;
    board.error_level = OFFLINE_WARNING_LEVEL;
    board.beep_times = 6;
    //offline_event_init(board);


    board.event = OFFLINE_BOARD_SMALL_YAW_2;
    board.error_level = OFFLINE_WARNING_LEVEL;
    board.beep_times = 6;
    //offline_event_init(board);


    board.event = OFFLINE_BOARD_CHASSIS;
    board.error_level = OFFLINE_ERROR_LEVEL;
    board.beep_times = 6;
    offline_event_init(board);

#endif 

#ifdef BOARD_CHASSIS
    board.event = OFFLINE_BOARD_BIG_YAW;
    board.beep_times = 6;
    offline_event_init(board);
#endif 

    return RT_EOK;
}
INIT_APP_EXPORT(board_com_init);


static void CANCommResetRx()
{
    // 当前已经收到的buffer清零
    rt_memset(board_com.raw_recvbuf, 0, board_com.cur_recv_len);
    board_com.recv_state = 0;   // 接收状态重置
    board_com.cur_recv_len = 0; // 当前已经收到的长度重置
}

static void board_com_process(struct rt_can_msg rxmsg){
    /* 当前接收状态判断 */
    if (rxmsg.data[0] == CAN_COMM_HEADER && board_com.recv_state == 0) // 之前尚未开始接收且此次包里第一个位置是帧头
    {
        //LOG_D("rxmsg id: %d\n",rxmsg.data[1]);
        if (rxmsg.data[1] == board_com.recv_data_len) // 如果这一包里的datalen也等于我们设定接收长度(这是因为暂时不支持动态包长)
        {
            board_com.recv_state = 1; // 设置接收状态为1,说明已经开始接收
        }
        else
            return; // 直接跳过即可
    }

    if (board_com.recv_state) // 已经收到过帧头
    {
        
        // 如果已经接收到的长度加上当前一包的长度大于总buf len,说明接收错误
        if (board_com.cur_recv_len + rxmsg.len > board_com.recv_buf_len)
        {
            CANCommResetRx();
            return; // 重置状态然后返回
        }

        // 直接把当前接收到的数据接到buffer后面
        rt_memcpy(board_com.raw_recvbuf + board_com.cur_recv_len, rxmsg.data, rxmsg.len);
        board_com.cur_recv_len += rxmsg.len;

        // 收完这一包以后刚好等于总buf len,说明已经收完了
        if (board_com.cur_recv_len == board_com.recv_buf_len)
        {
            // 如果buff里本tail的位置等于CAN_COMM_TAIL
            if (board_com.raw_recvbuf[board_com.recv_buf_len - 1] == CAN_COMM_TAIL)
            { // 通过校验,复制数据到unpack_data中
                if (board_com.raw_recvbuf[board_com.recv_buf_len - 2] == crc_8(board_com.raw_recvbuf + 2, board_com.recv_data_len))
                { // 数据量大的话考虑使用DMA
                    rt_memcpy(board_com.unpacked_recv_data, board_com.raw_recvbuf + 2, board_com.recv_data_len);
                    board_com.update_flag = 1;           // 数据更新flag置为1
                    //LOG_D("recv data success\n");
                }
            }
            CANCommResetRx();
            return; // 重置状态然后返回
        }
    }
}

void board_recv(struct rt_can_msg rxmsg)
{
    #ifdef BOARD_SMALL_YAW_1
    //防止烧错代码，出现多个相同设备的情况
    if (rxmsg.id == BOARD_SMALL_YAW_1_ID)
    {
        aRGB_led_show(LED_White);
        beep_set_tune(1000000,300000);
        RT_ASSERT(0);
    }
    if (rxmsg.id == BOARD_CHASSIS_ID)
    {
        offline_event_time_update(OFFLINE_BOARD_CHASSIS);
        board_com_process(rxmsg);
    }
    if (rxmsg.id == BOARD_BIG_YAW_ID)
    {
        offline_event_time_update(OFFLINE_BOARD_BIG_YAW);
        board_com_process(rxmsg);
    }

#endif 
#ifdef BOARD_SMALL_YAW_2
    //防止烧错代码，出现多个相同设备的情况
    if (rxmsg.id == BOARD_SMALL_YAW_2_ID)
    {
        aRGB_led_show(LED_White);
        beep_set_tune(1000000,300000);
        RT_ASSERT(0);
    }
    if (rxmsg.id == BOARD_CHASSIS_ID)
    {
        offline_event_time_update(OFFLINE_BOARD_CHASSIS);
        board_com_process(rxmsg);
    }
    if (rxmsg.id == BOARD_BIG_YAW_ID)
    {
        offline_event_time_update(OFFLINE_BOARD_BIG_YAW);
        board_com_process(rxmsg);
    }

#endif 
#ifdef BOARD_BIG_YAW
    //防止烧错代码，出现多个相同设备的情况
    if (rxmsg.id == BOARD_BIG_YAW_ID)
    {
        aRGB_led_show(LED_White);
        //beep_set_tune(1000000,300000);
        LOG_W("common device find,please check board define\n");
        RT_ASSERT(0);
    }
    if (rxmsg.id == BOARD_SMALL_YAW_1_ID)
    {
        offline_event_time_update(OFFLINE_BOARD_SMALL_YAW_1);
        //board_com_process(rxmsg);
    }
    if (rxmsg.id == BOARD_SMALL_YAW_2_ID)
    {
        offline_event_time_update(OFFLINE_BOARD_SMALL_YAW_2);
        //board_com_process(rxmsg);
    }
    if (rxmsg.id == BOARD_CHASSIS_ID)
    {
        offline_event_time_update(OFFLINE_BOARD_CHASSIS);
        board_com_process(rxmsg);
    }
#endif 

#ifdef BOARD_CHASSIS
    //防止烧错代码，出现多个相同设备的情况
    if (rxmsg.id == BOARD_CHASSIS_ID)
    {
        aRGB_led_show(LED_White);
        beep_set_tune(1000000,300000);
        RT_ASSERT(0);
    }
    if (rxmsg.id == BOARD_BIG_YAW_ID)
    {
        offline_event_time_update(OFFLINE_BOARD_BIG_YAW);
        board_com_process(rxmsg);
    }
#endif 
    
}


static void CANSetDLC(rt_uint8_t dlc)
{
    board_com.board_tx.txmsg.len = dlc;
}
void board_send(rt_uint8_t *data)
{
    if (board_com.board_tx.txmsg.id ==RT_NULL)
    {
        LOG_E("please config board_com\n");
        RT_ASSERT(0);
    }
    static rt_uint8_t crc8;
    static rt_uint8_t send_len;

    // 将data copy到raw_sendbuf中,计算crc8
    rt_memcpy(board_com.raw_sendbuf + 2, data, board_com.send_data_len);
    crc8 = crc_8(data, board_com.send_data_len);
    board_com.raw_sendbuf[2 +board_com.send_data_len] = crc8;

    // CAN单次发送最大为8字节,如果超过8字节,需要分包发送
    for (size_t i = 0; i < board_com.send_buf_len; i += 8)
    { // 如果是最后一包,send len将会小于8,
        send_len = board_com.send_buf_len- i >= 8 ? 8 : board_com.send_buf_len- i;
        CANSetDLC(send_len);
        rt_memcpy(&board_com.board_tx.txmsg.data, board_com.raw_sendbuf + i, send_len);
        rt_device_write(*board_com.board_tx.can_handle,0,&board_com.board_tx.txmsg,sizeof(board_com.board_tx.txmsg));
    }
}

void *CANCommGet()
{
    board_com.update_flag = 0; // 读取后将更新flag置为0
    return board_com.unpacked_recv_data;
}







